﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Coupons.Services
{
	/// <summary>
	/// Service de gestion des coupons de reduction
	/// </summary>
	public class IncentiveService : ERPStore.Services.IIncentiveService
	{
		public IncentiveService(
			ERPStore.Services.IAccountService accountService,
			AdminIncentiveService adminIncentiveService,
			EventBrokR.IPublisher publisher
			)
		{
			this.AccountService = accountService;
			this.AdminIncentiveService = adminIncentiveService;
			this.EventPublisher = publisher;
		}

		protected ERPStore.Services.IAccountService AccountService { get; private set; }
		protected AdminIncentiveService AdminIncentiveService { get; private set; }
		protected EventBrokR.IPublisher EventPublisher { get; private set; }

		#region IIncentiveService Members

		public virtual IEnumerable<ERPStore.Models.BrokenRule> ValidateUse(ERPStore.Models.OrderCart cart, string couponCode, ERPStore.Models.UserPrincipal principal)
		{
			if (cart == null
				|| couponCode.IsNullOrEmpty())
			{
				return null;
			}

			var coupon = AdminIncentiveService.GetCouponByCode(couponCode);
			if (coupon == null)
			{
				var r = new List<ERPStore.Models.BrokenRule>();
				r.AddBrokenRule("couponcode", "Ce code est inconnu");
				return r;
			}

			foreach (Models.CartDiscount discount in cart.DiscountList)
			{
				discount.CouponSource = AdminIncentiveService.GetCouponByCode(discount.Code);
			}

			var provider = AdminIncentiveService.GetProviderInstance(coupon.ProviderName); 
			provider.Coupon = coupon;
			var result = provider.ValidateUse(cart, principal);

			return result;
		}

		public virtual void AddCoupon(ERPStore.Models.OrderCart cart, string couponCode, ERPStore.Models.UserPrincipal principal)
		{
			if (couponCode == null)
			{
				return;
			}

			var coupon = AdminIncentiveService.GetCouponByCode(couponCode);
			if (coupon == null)
			{
				return;
			}

			var discount = AdminIncentiveService.GenerateDiscount();

			var provider = AdminIncentiveService.GetProviderInstance(coupon.ProviderName);
			provider.Coupon = coupon;
			provider.ApplyDiscountTo(discount, cart, principal);
			discount.InternalEntityId = cart.Id;
			discount.Code = coupon.Code;
			
			AdminIncentiveService.SaveDiscount(discount);
			EventPublisher.PublishAsync<ERPStore.Web.Events.AddCouponToCart>(new Web.Events.AddCouponToCart()
			{
				CartCode = cart.Code,
				CouponCode = couponCode,
			});
			LoadCouponList(cart);
		}

		public void RemoveCoupon(ERPStore.Models.OrderCart cart, string couponCode, ERPStore.Models.UserPrincipal principal)
		{
			if (couponCode.IsNullOrEmpty())
			{
				return;
			}
			var discount = cart.DiscountList.FirstOrDefault(i => i.Code.Equals(couponCode, StringComparison.InvariantCultureIgnoreCase));
			if (discount == null)
			{
				return;
			}
			var coupon  = AdminIncentiveService.GetCouponByCode(discount.Code);
			if (coupon == null)
			{
				return;
			}

			var provider = AdminIncentiveService.GetProviderInstance(coupon.ProviderName);
			provider.RemoveDiscountFrom(cart, principal);
			AdminIncentiveService.DeleteDiscount(discount as Models.CartDiscount);
			EventPublisher.PublishAsync<ERPStore.Web.Events.RemoveCouponFromCart>(new Web.Events.RemoveCouponFromCart()
			{
				CartCode = cart.Code,
				CouponCode = couponCode,
			});

			LoadCouponList(cart);
		}

		public void LoadCouponList(ERPStore.Models.OrderCart cart)
		{
			AdminIncentiveService.LoadCouponList(cart);
		}

		public void Recalc(ERPStore.Models.OrderCart cart, ERPStore.Models.UserPrincipal principal)
		{
			if (cart.DiscountList.IsNullOrEmpty())
			{
				return;
			}

			// Copie des remises en cours sur le panier
			var clonedList = new List<Models.CartDiscount>();
			foreach (Models.CartDiscount item in cart.DiscountList)
			{
				clonedList.Add(item);
			}

			cart.DiscountList = new List<Models.CartDiscount>();
			while (true)
			{
				var discount = clonedList.FirstOrDefault();
				if (discount == null)
				{
					break;
				}

				clonedList.Remove(discount);

				var coupon = AdminIncentiveService.GetCouponByCode(discount.Code);
				if (coupon == null)
				{
					continue;
				}

				var provider = AdminIncentiveService.GetProviderInstance(coupon.ProviderName);
				provider.Coupon = coupon;
				discount.CouponSource = coupon;

				var br = provider.ValidateUse(cart, principal);
				if (!br.IsNullOrEmpty())
				{
					AdminIncentiveService.DeleteDiscount(discount);
					continue;
				}

				var existingDiscountAmount = discount.Discount;
				provider.ApplyDiscountTo(discount as Models.CartDiscount, cart, principal);
				if (existingDiscountAmount != discount.Discount)
				{
					AdminIncentiveService.SaveDiscount(discount as Models.CartDiscount);
				}

				((List<Models.CartDiscount>)cart.DiscountList).Add(discount);
			}
		}

		#endregion



	}
}
